;1. 该系统能提供信息录入、查询、最终成绩排序功能 及 分数统计信息显示
;（各个总成绩分数段的人数、平均分、最高分、最低分）。
;2. 信息录入包括：学生的姓名、学号、及 16 次实验成绩和一次课程设计
;成绩。（通过键盘输入）
;3. 该系统能自动计算学生的最终成绩，按照平时实验成绩占 40%，课程设
;计成绩占 60%计算。
;4. 查询功能的查询方式需在显示界面有提示是 按姓名查询还是 学号查询。
;5. 成绩排序默认按照 从高到低排序。排序显示要求同时显示学生的姓名、
;学号、平时实验成绩、课程设计成绩、总成绩、及排名。
;6. 各个总成绩分数段的人数的统计按照：90-100 一个分数段；80-89 一个
;分数段；60-79 一个分数段；60 以下一个分数段。

;以下是代码实现：
assume cs:code, ds:data,ss:stack
data segment
    welcome db '__        __   _                            _        ',0dh,0ah
            db '\ \      / /__| | ___ ___  _ __ ___   ___  | |_ ___  ',0dh,0ah
            db ' \ \ /\ / / _ \ |/ __/ _ \| |_ ` _ \ / _ \ | __/ _ \ ',0dh,0ah
            db '  \ V  V /  __/ | (_| (_) | | | | | |  __/ | || (_) |',0dh,0ah
            db '   \_/\_/ \___|_|\___\___/|_| |_| |_|\___|  \__\___/ ',0dh,0ah,'$'
                                                    
    menu            db    0dh,0ah,'Please enter a number(1-6)',0dh,0ah
        db'------------------------------------------------------------------------------',0dh,0ah
        db'     *1: Input student basic information and seventeen assignment scores      ',0dh,0ah  ;输入学生基本信息和十七次成绩
        db'                        *2: Search through student ID                         ',0dh,0ah  ;通过学号查询成绩
        db'                       *3: Search through student NAME                        ',0dh,0ah  ;通过姓名查询成绩
        db'                           *4: Sort by total score                            ',0dh,0ah  ;对成绩进行排序
        db'               *5: Analyze statistical data by score segmentation             ',0dh,0ah  ;分析统计数据通过分数段
        db'                             *6: Exit the system                              ',0dh,0ah  ;退出系统
        db'------------------------------------------------------------------------------',0dh,0ah,'$'
    choice          db    '--------------------------please input the choice.---------------------------',0dh,0ah,'$'     ;输入选择
    error0          db    '-------------------------The input is incorrect!--------------------------',0dh,0ah,'$'        ;输入错误
    line            db    0dh,0ah,'$'                                                                                     ;换行
    thank           db    ' _______ _                 _       ',0dh,0ah
                    db    '|__   __| |               | |      ',0dh,0ah
                    db    '   | |  | |__   __ _ _ __ | | __   ',0dh,0ah
                    db    '   | |  |  _ \ / _` |  _ \| |/ /   ',0dh,0ah
                    db    '   | |  | | | | (_| | | | |   <    ',0dh,0ah
                    db    '   |_|  |_| |_|\__,_|_| |_|_|\_\   ',0dh,0ah,'$'
                    score db'    ID    |     NAME     |01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 final','$'         ;输入分数
    studentNum      db    'Please enter the number of students:','$'                                                      ;输入学生数量
    SearchID        db    'Which ID do you want to search through:','$'                                                   ;输入学生id查询
    SearchSuccess   db    '-----------------------------Search successful!-----------------------------',0dh,0ah,'$'      ;查询成功
    showname        db    '                Name:','$'
    showid          db    '                                           ID:','$'
    showNormalGrade db    '           Normal_Grade:','$'                                                                  ;平时成绩
    showbig         db    '        Design_Grade:','$'                                                                     ;大作业
    showfinal       db    '        Final_Grade:','$'                                                                      ;最终成绩
    Searchname      db    'Which name do you want to search through:','$'
    sort            db    '    ID    |     NAME     |Normal_Grade   Design_Grade     Final_Grade     Rank',0dh,0ah,'$'
    show            db    '--------------------------Analyze statistical data--------------------------',0dh,0ah,'$'
    show0           db    '                           90-100:','$'
    show1           db    '                            80-89:','$'
    show2           db    '                            60-79:','$'
    show3           db    '                             0-59:','$'
    show4           db    '                    average grade:','$'
    show5           db    '                    highest grade:','$'
    show6           db    '                     lowest grade:','$'
    space           db    '           ','$'                                                                               ;空格——排版优化
    space0          db    ' ','$'                                                                                         ;空格——排版优化
    space1          db    '    ','$'                                                                                      ;空格——排版优化
    name1           db    12,?,12 dup('$')                                                                                ;存放姓名
    name2           db    12,?,12 dup('$')                                                                                ;第一个字节不确定，后11个字节初始化为'$'，存放结束符
    name3           db    12,?,12 dup('$')
    name4           db    12,?,12 dup('$')
    name5           db    12,?,12 dup('$')
    name6           db    12,?,12 dup('$')
    name7           db    12,?,12 dup('$')
    name8           db    12,?,12 dup('$')
    name9           db    12,?,12 dup('$')
    name10          db    12,?,12 dup('$')
    name11          db    12,?,12 dup('$')                                                                                ;可继续增加存放量
    id1             db    12,?,12 dup('$')                                                                                ;存放ID
    id2             db    12,?,12 dup('$')
    id3             db    12,?,12 dup('$')
    id4             db    12,?,12 dup('$')
    id5             db    12,?,12 dup('$')
    id6             db    12,?,12 dup('$')
    id7             db    12,?,12 dup('$')
    id8             db    12,?,12 dup('$')
    id9             db    12,?,12 dup('$')
    id10            db    12,?,12 dup('$')
    id11            db    12,?,12 dup('$')                                                                                ;可继续增加存放量
    student_count   dw    0                                                                                               ;学生数量
    highest_score   dw    0                                                                                               ;最高成绩
    lowest_score    dw    100                                                                                             ;最低成绩
    average_score   dw    0                                                                                               ;平均成绩
    tmp             dw    0                                                                                               ;用来计算的临时空间
    tmp1            dw    0
    tmp2            dw    0
    ten             dw    10                                                                                              ;数字十，方便运算
    score_analyze   dw    0,0,0,0,'$'                                                                                     ;保存四个分数段中的人数
    score_enter     dw    4,2,1                                                                                           ;分数输入时需要的辅助数字便于计算
    normal_score    dw    20 dup(?)                                                                                       ;平时成绩，大作业成绩和总成绩
    big_score       dw    20 dup(?)                                                                                       ;大作业成绩
    final_score     dw    20 dup(?)                                                                                       ;总成绩
    rank            dw    20 dup(0)                                                                                       ;排名
    divnum          dw    1000,100,10,1                                                                                   ;除数,数字转ascll用的
    result          db    0,0,0,0,'$'                                                                                     ;存放除的结果
    funtable        dw    function1,function2,function3,function4,function5,function6
    idtable         dw    id1,id2,id3,id4,id5,id6,id7,id8,id9,id10,id11
    nametable       dw    name1,name2,name3,name4,name5,name6,name7,name8,name9,name10,name11
data ends
    
stack segment stack
          db 256 dup (0)
stack ends
;------------------------------宏定义------------------------------------
;------------------------------输出提示语-------------------------------
out_dx macro str          ;用于输出提示语
           push dx
           push ax
           lea  dx,str
           mov  ah,09h
           int  21h
           pop  ax
           pop  dx
endm
;------------------------------保护寄存器-------------------------------
push_all macro
             push ax
             push bx
             push cx
             push dx
             push si
             push di
endm
pop_all macro
            pop di
            pop si
            pop dx
            pop cx
            pop bx
            pop ax
endm
;------------------------------将数字转为ascll码-------------------------------
; 定义output_ascii宏，用于将一个32位双字无符号整数转为ascll码并输出
output_ascii macro
                 local    ascll_0,ascll_1,ascll_2    ;定义局部标签
                 push_all
                 mov      si,offset divnum           ; 除数
                 mov      di,offset result           ;存放结果
                 mov      cx,4
    ascll_0:     
                 mov      dx,0
                 div      word ptr [si]
 
                 add      al,30h                     ;转为ascll码
                 mov      byte ptr [di],al
                 inc      di
                 add      si,2
                 mov      ax,dx
                 loop     ascll_0
 
                 mov      cx,3
                 mov      di,offset result
 
    ascll_1:     
                 cmp      byte ptr [di],'0'
                 jne      ascll_2
                 inc      di
                 loop     ascll_1
 
    ascll_2:     
                 mov      dx,di
                 mov      ah,9
                 int      21H
                 pop_all
endm
;------------------------------功能开始前的初始化值-------------------------------
begin_all macro
              mov ax,0
              mov bx,0
              mov cx,student_count
              mov dx,0
              mov di,0
              mov si,0
endm
;------------------------------宏定义结束------------------------------------
;------------------------------start-----------------------------------------
code segment
    start:      
    ;初始化寄存器
                mov          ax,data
                mov          ds,ax
                mov          es,ax
                mov          ax,stack
                mov          ss,ax
                mov          sp,256
    ;输出欢迎语
                out_dx       welcome
    start0:     
    ;输出菜单
                out_dx       menu
    start1:     
                out_dx       choice
    ;输入选择
                mov          al,01h
                mov          ah,0ch
                int          21h
                sub          al,30h
                cmp          al,0
                jb           exit0
                cmp          al,6
                ja           exit0
                mov          bx,0
                dec          al                       ;为了匹配数组下标
                mov          bl,al
                add          bx,bx                    ;需要翻倍bx，因为数组下标是偶数，以字节为单位
                out_dx       line
                call         funtable[bx]
                jmp          start0                   ;返回到菜单
    exit0:      
                out_dx       line                     ;输出换行
                out_dx       error0                   ;输出错误提示
                jmp          start1                   ;返回到菜单
    ;------------------------------function1输入-------------------------------
    function1:  
                push_all
                out_dx       studentNum
                mov          bx,0
    fun1_1:     
                mov          al,01h
                mov          ah,0ch
                int          21h                      ;输入学生数量
                sub          al,30h
                jb           fun1_2
                cmp          al,9
                ja           fun1_2                   ;小于9大于0则跳转，为一位数
 
                mov          ah,0                     ;两位数则继续执行
                xchg         ax,bx
                mul          ten[0]
                xchg         ax,bx
                add          bx,ax
                jmp          fun1_1
    fun1_2:     
                lea          si,student_count
                mov          word ptr [si],bx
 
                begin_all
                out_dx       line
                out_dx       score
       
    f1_1:       
    
                push         ax
                push         dx
                out_dx       line
                mov          dx,idtable[si]
                mov          al,0ah
                mov          ah,0ch
                int          21H                      ;输入学生的学号
                mov          ah,02h
                mov          dx,180dh                 ;设定光标到第24行13列
                int          10h
 
                mov          dx,nametable[si]
                mov          al,0ah
                mov          ah,0ch
                int          21H                      ;输入学生姓名
 
                mov          ah,02h
                mov          dx,181ah                 ;设定光标到第24行26列
                int          10h
    
                pop          dx
                pop          ax
 
                mov          tmp2,cx
                mov          cx,16
                mov          ax,0
 
    f1_2:       
                push         si
                push         ax
                push         bx
                mov          bx,0
    n1:         
                mov          al,01h
                mov          ah,0ch
                int          21h
 
                sub          al,30h                   ;改变为数字
                jl           n2                       ;小于0，跳转
                cmp          al,9                     ;大于9，跳转
                jg           n2
                cbw                                   ;AL的内容扩展到AH,形成AX中的字。
 
                xchg         ax,bx
                mul          ten[0]
                xchg         ax,bx
                add          bx,ax
                dec          score_enter[2]
                cmp          score_enter[2],0
                ja           n1
    n2:         
                mov          score_enter[2],2
                lea          si,tmp
                mov          word ptr [si],bx
                pop          bx
                pop          ax
                pop          si
 
 
                add          ax,tmp                   ;把16次平时成绩加起来
                mov          tmp,0
                out_dx       space0
                loop         f1_2
 
                mov          cx,tmp2                  ;除以16得到平时成绩
                mov          bl,16
                div          bl
                mov          dl,al
                mov          dh,0
                mov          normal_score[si],dx      ;放在ping_score中
 
                mov          tmp1,dx                  ;这里其实是x4，为了简便加了4次
                add          tmp1,dx                  ;(平时x4+大作业x6）/10
                add          tmp1,dx
                add          tmp1,dx
 
                push         si
                push         ax
                push         bx
                mov          bx,0
    n3:         
                mov          al,01h                   ;功能号和清除缓存区
                mov          ah,0ch
                int          21h
 
                sub          al,30h                   ;改变为数字
                jl           n4                       ;小于0，跳转
                cmp          al,9                     ;大于9，跳转
                jg           n4
                cbw                                   ;AL的内容扩展到AH,形成AX中的字。
 
                xchg         ax,bx
                mul          ten[0]                   ;*10
                xchg         ax,bx
                add          bx,ax
                dec          score_enter[2]           ;1
                cmp          score_enter[2],0
                ja           n3                       ;大于则跳转
    n4:         
                mov          score_enter[2],2
                lea          si,tmp
                mov          word ptr [si],bx
                pop          bx
                pop          ax
                pop          si
    
                mov          dx,tmp
                mov          tmp,0
                mov          big_score[si],dx         ;对应大作业成绩
 
                add          tmp1,dx                  ;大作业*6，加上去
                add          tmp1,dx
                add          tmp1,dx
                add          tmp1,dx
                add          tmp1,dx
                add          tmp1,dx
 
 
                mov          ax,tmp1
                mov          bl,10
                div          bl                       ;除以10，得到最终成绩
                mov          dl,al
                mov          dh,0
                mov          final_score[si],dx       ;存入最终成绩
 
    ;计算各个分数段的人数
                cmp          dx,60                    ;跳转到相应的计数部分
                jl           f1_3
 
                cmp          dx,80
                jl           f1_4
 
                cmp          dx,90
                jl           f1_5
 
                inc          score_analyze[6]         ;score_analyze是各个分数段的统计人数，
                jmp          f1_6
    f1_3:       
                inc          score_analyze[0]
                jmp          f1_6
    f1_4:       
                inc          score_analyze[2]
                jmp          f1_6
    f1_5:       
                inc          score_analyze[4]
                jmp          f1_6
 
    f1_6:       
                add          average_score,dx         ;总分累加
                cmp          dx,highest_score
                jng          f1_7
                call         highmove
    f1_7:       
                cmp          dx,lowest_score
                jnl          f1_8
                call         lowmove
    f1_8:       
                add          si,2
                dec          cx
                jcxz         f1ret
                jmp          near ptr f1_1
    f1ret:      
                pop_all
                ret
    highmove:   
                mov          highest_score,dx         ;改变最低成绩和最高成绩
                ret
    lowmove:    
                mov          lowest_score,dx
                ret
    ;----------------------function2查找学号-------------------------------
    function2:  
                push_all
                begin_all
                out_dx       SearchID
                push         ax
                push         dx
                mov          dx,idtable[20]           ;将学号输入到idtable最后一位处
                mov          al,0ah
                mov          ah,0ch
                int          21H
                pop          dx
                pop          ax
                out_dx       line
    f2_0:       
                mov          tmp2,cx                  ;tmp2储存学生数量
                mov          cx,10                    ;重复比较十位，故ID最大只能有十位
                lea          di,id11
                add          di,2
                mov          si,idtable[bx]
                add          si,2
                repz         cmpsb
                jz           f2_1
                add          bx,2
                mov          cx,tmp2
                loop         f2_0
                out_dx       line
                out_dx       error0
                jmp          f2_2
    f2_1:                                             ; 查找成功
                out_dx       SearchSuccess
                out_dx       line
                out_dx       showid
                mov          dx,idtable[bx]
                add          dx,2
                mov          ah,9h
                int          21h                      ;显示id
                out_dx       showname
                mov          dx,nametable[bx]
                add          dx,2
                mov          ah,9h
                int          21h                      ;显示姓名
                out_dx       line
                out_dx       showNormalGrade
                mov          ax, normal_score[bx]
                output_ascii
                out_dx       showbig
                mov          ax,final_score[bx]
                output_ascii

                out_dx       showfinal
                mov          ax,final_score[bx]
                output_ascii
                out_dx       line
    f2_2:                                             ;重置空间，方便下次继续查询不会出错
                mov          bx,idtable[20]
                inc          bx
                mov          byte ptr [bx],0
                inc          bx
                mov          cx,10
    f2_3:       
                mov          byte ptr [bx],'$'
                inc          bx
                loop         f2_3
                pop_all
                ret
    ;------------------------------function3查找名字-------------------------------
    function3:  
                push_all
                begin_all
 
                out_dx       Searchname
                mov          dx,nametable[20]
                mov          al,0ah
                mov          ah,0ch
                int          21H                      ;输入姓名
                out_dx       line
    f3_0:       
                mov          tmp2,cx
                mov          cx,10
                lea          di,name11
                add          di,2
                mov          si,nametable[bx]
                add          si,2
                repz         cmpsb
                jz           f3_1
                add          bx,2                     ;寻找下一个姓名
                mov          cx,tmp2
                loop         f3_0
                out_dx       line
                out_dx       error0
                jmp          f3_2
    f3_1:       
                out_dx       SearchSuccess
                out_dx       line
                out_dx       showid
                mov          dx,idtable[bx]
                add          dx,2
                mov          ah,9h
                int          21h                      ;显示id
                out_dx       showname
                mov          dx,nametable[bx]
                add          dx,2
                mov          ah,9h
                int          21h                      ;显示姓名
                out_dx       line
                out_dx       showNormalGrade
                mov          ax, normal_score[bx]
                output_ascii
                out_dx       showbig
                mov          ax,final_score[bx]
                output_ascii
                out_dx       showfinal
                mov          ax,final_score[bx]
                output_ascii

                out_dx       line
    f3_2:                                             ;重置
                mov          bx,nametable[40]
                inc          bx
                mov          byte ptr [bx],0
                inc          bx
                mov          cx,10
    f3_3:       
                mov          byte ptr [bx],'$'
                inc          bx
                loop         f3_3
 
                pop_all
                ret
    ;------------------------------function4排序-------------------------------
    function4:  
                push_all
                begin_all
                mov          dx,student_count         ;count初始化，外循环次数
                sub          dx,1                     ; i=student_count-1,减一是为了防止数组越界
    sort1:      
    ;mov bl,0
                cmp          dx,0
                jle          sortexit                 ;if i<=0, exit
                mov          cx,dx                    ; j<i
                mov          si,0                     ; j=0
    sort2:      
                mov          ax,final_score[si]
                cmp          ax,final_score[si+2]
                jle          no_exchange
                xchg         ax,final_score[si+2]     ;交换总成绩
                mov          final_score[si],ax
 
                mov          ax,big_score[si]         ;交换大作业成绩
                xchg         ax,big_score[si+2]
                mov          big_score[si],ax
    
                mov          ax,normal_score[si]      ;交换平时作业成绩
                xchg         ax,normal_score[si+2]
                mov          normal_score[si],ax
 
                mov          ax,nametable[si]         ;交换姓名
                xchg         ax,nametable[si+2]
                mov          nametable[si],ax
 
                mov          ax,idtable[si]           ;交换学号
                xchg         ax,idtable[si+2]
                mov          idtable[si],ax
    ;mov bl,0ffh
    no_exchange:
                add          si,2
                loop         sort2
                dec          dx
    ;cmp bl,0
                jmp          sort1
    sortexit:   
                mov          bx,0
                mov          cx,student_count
    rk:         
                mov          rank[bx],cx
                add          bx,2
                loop         rk
                mov          bx,0
                mov          cx,student_count
                out_dx       sort
    f4show:     
                out_dx       line
                mov          dx,idtable[bx]
                add          dx,2
                mov          ah,9h
                int          21H
                mov          ah,02h
                mov          dx,180dh
                int          10h
                mov          dx,nametable[bx]
                add          dx,2
                mov          ah,9h
                int          21H
                mov          ah,02h
                mov          dx,181ah
                int          10h
                out_dx       space1
                mov          ax,normal_score[bx]
                output_ascii
                out_dx       space
                mov          ax,big_score[bx]
                output_ascii
                out_dx       space
                mov          ax,final_score[bx]
                output_ascii
                out_dx       space
                mov          ax,rank[bx]
                output_ascii
                add          bx,2
                dec          cx
                jcxz         f4ret
                jmp          near ptr f4show
    f4ret:      
                pop_all
                ret
    ;------------------------------function5统计-------------------------------
    function5:  
                push_all
                begin_all
                mov          bx,student_count
 
                out_dx       show
                out_dx       line
    
                out_dx       show0
                mov          ax,score_analyze[6]
                output_ascii
                out_dx       line
 
                out_dx       show1
                mov          ax,score_analyze[4]
                output_ascii
                out_dx       line
    
                out_dx       show2
                mov          ax,score_analyze[2]
                output_ascii
                out_dx       line
    
                out_dx       show3
                mov          ax,score_analyze[0]
                output_ascii
                out_dx       line
    
                out_dx       show4
                mov          ax,average_score
                div          bl
                mov          dl,al
                mov          dh,0
                mov          ax,dx
                output_ascii
                out_dx       line
 
                out_dx       show5
                mov          ax,highest_score
                output_ascii
                out_dx       line
 
                out_dx       show6
                mov          ax,lowest_score
                output_ascii
                out_dx       line
                pop_all
                ret
    ;------------------------------function6退出-------------------------------
    function6:  
                out_dx       thank                    ;输出感谢
                mov          ax,4c00h
                int          21h
                ret
 
code ends
end start
